﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using System.Globalization;
using System.Security;

namespace MyLibrary.Logger
{
    /// <summary>
    /// 获取调用对象的信息
    /// </summary>
    internal class CallerInfo
    {
        const string NA = "?";

        #region 属性
        string _className = NA;

        public string ClassName
        {
            get { return _className; }
        }

        string _fileName = NA;

        public string FileName
        {
            get { return _fileName; }
        }
        string _lineNumber = NA;

        public string LineNumber
        {
            get { return _lineNumber; }
        }

        string _methodName = NA;

        public string MethodName
        {
            get { return _methodName; }
        }
        #endregion

        #region 构造函数
        public CallerInfo(Type callerType)
        {
            if (callerType != null)
            {
                try
                {
                    StackTrace st = new StackTrace(true);
                    int frameIndex = 0;

                    while (frameIndex < st.FrameCount)
                    {
                        StackFrame frame = st.GetFrame(frameIndex);
                        //如果跟踪堆栈中的方法是由caller内的方法
                        if (frame != null && frame.GetMethod().DeclaringType == callerType)
                            break;
                        frameIndex++;
                    }
                    while (frameIndex < st.FrameCount)
                    {
                        StackFrame frame = st.GetFrame(frameIndex);

                        if(frame != null  && frame.GetMethod().DeclaringType != callerType)
                            break;
                        frameIndex++;
                    }

                    if (frameIndex < st.FrameCount)
                    {
                        StackFrame locationFrame = st.GetFrame(frameIndex);

                        if (locationFrame != null)
                        {
                            MethodBase method = locationFrame.GetMethod();
                            if (method != null)
                            {
                                _methodName = method.Name;
                                if (method.DeclaringType != null)
                                    _className = method.DeclaringType.FullName;
                            }
                        }
                        _fileName = locationFrame.GetFileName();
                        _lineNumber = locationFrame.GetFileLineNumber().ToString(NumberFormatInfo.InvariantInfo);
                    }
                }
                catch(SecurityException)
                {
                    Debug.WriteLine("无法获取调用者的属性信息");
                }
            }
        }

       
        public CallerInfo(object caller)
            : this(typeof(caller))
        {

        }
        
        #endregion

        public override string ToString()
        {
            return _className + "." + _methodName + "(" + _fileName + ":" + _lineNumber + ")";
        }
    }
}
